/**
 * @(#)Manager.java		1.0		17/04/2012
 */
package upm.pb4agent.team8;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;

import jade.content.ContentElement;
import jade.content.lang.Codec;
import jade.content.lang.sl.SLCodec;
import jade.content.onto.Ontology;
import jade.content.onto.basic.Action;
import jade.core.AID;
import jade.core.Agent;
import jade.core.behaviours.SimpleBehaviour;
import jade.domain.DFService;
import jade.domain.FIPAException;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.lang.acl.ACLMessage;
import jade.wrapper.AgentContainer;
import jade.wrapper.AgentController;
import upm.pb4agent.common.Constant;
import upm.pb4agent.ontology.Dock;
import upm.pb4agent.ontology.DockDesignation;
import upm.pb4agent.ontology.Owns;
import upm.pb4agent.ontology.PB4AgentOntology;
import upm.pb4agent.ontology.Registration;
import upm.pb4agent.ontology.RegistrationForm;
import upm.pb4agent.ontology.SubscribeReferee;
import upm.pb4agent.ontology.TeamID;
import upm.pb4agent.team8.Common.PB4Properties;
import upm.pb4agent.team8.Common.PB4Utils.MsgTypes;
import upm.pb4agent.team8.Common.RowerAttribute;
import upm.pb4agent.team8.Common.PB4Utils;

public class Manager extends Agent
{
	private static final long serialVersionUID = 4283953927888777831L;
	
	private List<RowerMgr> RowerMgrs = new ArrayList<RowerMgr>();	 
	
	private Codec codec = new SLCodec();
	private Ontology ontology = PB4AgentOntology.getInstance();

	protected void setup() {

		PB4Utils.Console.WriteLine( getLocalName() + ": Enters the system");

		getContentManager().registerLanguage(codec);
		getContentManager().registerOntology(ontology);

		addBehaviour(new RegisterRowerToRegistrationDeskBehavior(this));
		addBehaviour(new AwaitRegistrationReplyBehavior(this));
		SetupRowers();
	}

	private void SetupRowers()
	{
		CreateRowers();		
	}
	
	private void CreateRowers()
	{
		int numRowers =4;
		for (int i = 1; i <= numRowers; i++) 
		{
			RowerMgrs.add(new RowerMgr(Constant.ROWER_NAME+Constant.TEAM_ID+Integer.toString(i), this.getContainerController()));
		}
		AssignRowersToDocks();
		for (RowerMgr r : RowerMgrs)
		{
			r.Start();
		}		
	}
	
	private void AssignRowersToDocks()
	{
		Map<String, Float> map = new HashMap<String, Float>();
		for (RowerMgr r : RowerMgrs)
		{
			map.put(r.GetNickName(), r.GetWeightedAttribute());
		}
		
		Map<String, Float> sortedMap = PB4Utils.SortHashMap(map);
		int k=0;
		for (String key : sortedMap.keySet())
		{
			switch (k)
			{
				case 0:
					FindRowerMgr(key).SetDock(Constant.DockNumber.A.toString());
					PB4Utils.Console.WriteLine("Rower " + key + " was assigned to \"Dock A \" - Weighted Value =" + sortedMap.get(key).toString());
					break;
				case 1:
					FindRowerMgr(key).SetDock(Constant.DockNumber.B.toString());				
					PB4Utils.Console.WriteLine("Rower " + key + " was assigned to \"Dock B \" - Weighted Value ="+ sortedMap.get(key).toString());
					break;
				case 2:
					FindRowerMgr(key).SetDock(Constant.DockNumber.C.toString());				
					PB4Utils.Console.WriteLine("Rower " + key + " was assigned to \"Dock C \" - Weighted Value ="+ sortedMap.get(key).toString());
					break;
				case 3:
					FindRowerMgr(key).SetDock(Constant.DockNumber.D.toString());				
					PB4Utils.Console.WriteLine("Rower " + key + " was assigned to \"Dock D \" - Weighted Value ="+ sortedMap.get(key).toString());
					break;
			}
			k++;
		}		
	}
		
	class RegisterRowerToRegistrationDeskBehavior extends SimpleBehaviour
	{
		private static final long serialVersionUID = 6583615439716568340L;
		private Agent _agent;
		private boolean _finished = false;
		
		public RegisterRowerToRegistrationDeskBehavior(Agent agent) {
			super(agent);
			_agent = agent;
		}

		@Override
		public void action() {
			
			AID registrationDeskAID;

			TeamID teamID = new TeamID();
			teamID.setValue(Constant.TEAM_ID);
			
			registrationDeskAID = PB4Utils.TryFindAgent( _agent, Constant.REGISTRATION_DESK);
			if (registrationDeskAID !=null)
			{
				//Create Ontology Data
				RegistrationForm registrationForm = new RegistrationForm();
				registrationForm.setTeamID(teamID);
				for (RowerMgr r : RowerMgrs)
				{
					registrationForm.addDockDesignation(r.GetDockDesignation());
				}
				Registration registration=new Registration();
				registration.setRegistrationForm(registrationForm);
				
				PB4Utils.Console.WriteLine("Trying to register Team  with the Registration Desk ",  MsgTypes.Low);
				PB4Utils.TrySendConceptMessage(ACLMessage.REQUEST, _agent, registrationDeskAID, registration);
				_finished = true;
			}
		}

		@Override
		public boolean done()
		{
			return _finished;
		}
	}

	class AwaitRegistrationReplyBehavior extends SimpleBehaviour
	{
		private static final long serialVersionUID = -7842952916094279836L;
		private boolean _finished= false;
		
		public AwaitRegistrationReplyBehavior(Agent agent)
		{
		}

		@Override
		public void action()
		{
			ACLMessage aclMessage = receive();
			if (aclMessage != null)
			{
				// Registration is valid
				if (aclMessage.getPerformative() == ACLMessage.INFORM)
				{
				}
				else if (aclMessage.getPerformative() == ACLMessage.REFUSE
						|| aclMessage.getPerformative() == ACLMessage.NOT_UNDERSTOOD)
				{
					for (RowerMgr r : RowerMgrs)
					{
						r.Kill();
					}
				}
			} 
		}

		@Override
		public boolean done() {
			return _finished;
		}
	}
	
	public class RowerMgr
	{
		private AgentContainer _agentContainer;
		private AgentController _agentController;
		private Dock _dock;
		private DockDesignation _dockDesignation;
		private String _nickName;		
		public String GetNickName()
		{
			return _nickName;
		}
		
		public DockDesignation GetDockDesignation()
		{
			return _dockDesignation;
		}
		
		public AID GetAID()
		{
			return new AID(_nickName, AID.ISLOCALNAME);
		}
		
		public void SetDock(String dock)
		{
			_dockDesignation.getDock().setName(dock);
		}
		
		private float _strength;
		public float GetStrength()
		{
			return _strength;
		}
		
		private float _resistance;
		public float GetResistance()
		{
			return _resistance;
		}
		
		private float _agility;
		public float Agility()
		{
			return _agility;
		}
		
		private String ID()
		{
			return _nickName.replace(Constant.ROWER_NAME+Constant.TEAM_ID, "");
		}
		
		private float GetWeightedAttribute()
		{
			return (float)(_strength * 0.35 + _resistance * 0.45 + _agility * 0.2);
		}

		RowerMgr(String nickName, AgentContainer container)
		{
			_nickName = nickName;
			_dock = new Dock();
			_dock.setName("1");
			
			_dockDesignation = new DockDesignation();
			_dockDesignation.setRowerID(GetAID());
			_dockDesignation.setDock(_dock);
			
			_agentContainer = container;
			_agentController = CreateRowerController(_nickName);
			GetRowerCharacteristics();
		}
		
		private void GetRowerCharacteristics()
		{
			/*
			_strength = PB4Utils.PropertyReader.GetIntKey(Constant.ROWER_STRENGTH.replace("%", this.ID()));
			_resistance = PB4Utils.PropertyReader.GetIntKey(Constant.ROWER_RESISTANCE.replace("%", this.ID()));
			_agility = PB4Utils.PropertyReader.GetIntKey(Constant.ROWER_AGILITY.replace("%", this.ID()));*/
			RowerAttribute attribute = PB4Properties.RowerAttributes.get(_nickName);
			_strength = attribute.Strength;
			_resistance = attribute.Resistance;
			_agility = attribute.Agility;
		}
		
		public void Start()
		{
			try
			{
				_agentController.start();
			}
			catch (Exception e) 
			{
				System.out.println("Can not Start Agent" + e.getStackTrace());
			}
		}
		
		public void Kill()
		{
			try
			{
				_agentController.kill();
			}
			catch (Exception e)
			{
				System.out.println("Can not Kill Agent" + e.getStackTrace());
			}
		}
		
		private AgentController CreateRowerController(String nickName )
		{
			try
			{
				return _agentContainer.createNewAgent(nickName, "upm.pb4agent.team8.Rower", new Object[] {_dock});
			}
			catch (Exception e) 
			{
				System.out.println("Can not crete Agent" + e.getStackTrace());
				return null;
			}
		}

	}

	private RowerMgr FindRowerMgr(String key)
	{
		RowerMgr rower = null;
		for (RowerMgr r : RowerMgrs)
		{
			if (r.GetNickName()==key)
				rower = r;
		}
		return rower;
	}
}
